import numpy as np클래스 공부 5단계
- 지난시간까지 배운것: RPC자료형에 한정해서 print() 등의 기능을 조작할 수 있었다. (재정의 할 수 있었다.)
- 이번시간에 배울것: 특정자료형에 한정하여 print 이외의 파이썬 내부기능을 조작하여 보자. (재정의하여 보자)
motive
a=1
b=2type(a)int
a+b3
- a라는 인스턴스와 b라는 인스턴스를 + 라는 기호가 연결하고 있다.
a=[1,2]
b=[3,4]
a+b[1, 2, 3, 4]
- a라는 인스턴스와 b라는 인스턴스를 + 라는 기호가 연결하고 있다.
- 동작이 다른 이유?
클래스를 배우기 이전: int자료형의
+는 “정수의 덧셈”을 의미하고 list 자료형의+는 “자료의 추가”를 의미한다.클래스를 배운 이후: 아마 클래스는
+라는 연산을 정의하는 숨겨진 메소드가 있을 것이다. (print가 그랬듯이) 그런데 int 클래스에서는 그 메소드를 “정수의 덧셈”이 되도록 정의하였고 list클래스에서는 그 메소드를 “자료의 추가”를 의미하도록 정의하였다.
a=1
b=2a.__add__<method-wrapper '__add__' of int object at 0x70c560>
dir(a)['__abs__',
'__add__',
'__and__',
'__bool__',
'__ceil__',
'__class__',
'__delattr__',
'__dir__',
'__divmod__',
'__doc__',
'__eq__',
'__float__',
'__floor__',
'__floordiv__',
'__format__',
'__ge__',
'__getattribute__',
'__getnewargs__',
'__gt__',
'__hash__',
'__index__',
'__init__',
'__init_subclass__',
'__int__',
'__invert__',
'__le__',
'__lshift__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__neg__',
'__new__',
'__or__',
'__pos__',
'__pow__',
'__radd__',
'__rand__',
'__rdivmod__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rfloordiv__',
'__rlshift__',
'__rmod__',
'__rmul__',
'__ror__',
'__round__',
'__rpow__',
'__rrshift__',
'__rshift__',
'__rsub__',
'__rtruediv__',
'__rxor__',
'__setattr__',
'__sizeof__',
'__str__',
'__sub__',
'__subclasshook__',
'__truediv__',
'__trunc__',
'__xor__',
'bit_length',
'conjugate',
'denominator',
'from_bytes',
'imag',
'numerator',
'real',
'to_bytes']
a.__add__(b)3
b.__add__(a)3
a=[1,2]
b=[3,4]a.__add__(b)[1, 2, 3, 4]
b.__add__(a)[3, 4, 1, 2]
- a+b는 사실 내부적으로 a.__add__(b)의 축약구문이다. 따라서 먄악 a.__add__(b)의 기능을 바꾸면 (재정의하면) a+b의 기능도 바뀔 것이다.
__add__
- 예제
class Student:
def __init__(self, age=20.0, semester=1):
self.age = age
self.semester = semester
print("입학을 축하합니다. 나이는 {}이고 현재 {}학기 입니다.".format(self.age, self.semester))
def __add__(self,val):
# val == 0: 휴학
# val == 1: 등록
if val==0:
self.age=self.age+0.5
elif val==1:
self.age=self.age+0.5
self.semester= self.semester+1
def _repr_html_(self):
html_str = """
나이: {}<br/>
학기: {}<br/>
"""
return html_str.format(self.age, self.semester)iu = Student()입학을 축하합니다. 나이는 20.0이고 현재 1학기 입니다.
iu.semester1
iu # 클래스가 저장되어있는 주소를 _repr_html_ 통해서 바꿔즘학기: 1
iu + 1 #1학년 2학기 등록
iu학기: 2
iu + 0 # 휴학
iu학기: 2
- 연산을 연속으로 하고 싶다.
iu + 1 + 0 + 0 + 0 + 0TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
- 에러의 이유?
1+1+1 #이거는 되는데?3
(1+1)+13
_a = (1+1)
type(_a)int
_a + 1 # 이 연산은 int인스턴스 + int인스턴스 3
(안되는거)
iu+1+1TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
_a=iu+1type(_a)NoneType
_a+1TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
- 에러를 해결하는 방법: iu+1의 결과로 Student 클래스의 인스턴스가 리턴되면 된다.
class Student:
def __init__(self, age=20.0, semester=1):
self.age = age
self.semester = semester
print("입학을 축하합니다. 나이는 {}이고 현재 {}학기 입니다.".format(self.age, self.semester))
def __add__(self,val):
# val == 0: 휴학
# val == 1: 등록
if val==0:
self.age=self.age+0.5
elif val==1:
self.age=self.age+0.5
self.semester= self.semester+1
return self
def _repr_html_(self):
html_str = """
나이: {}<br/>
학기: {}<br/>
"""
return html_str.format(self.age, self.semester)iu = Student()입학을 축하합니다. 나이는 20.0이고 현재 1학기 입니다.
iu + 1 # __add__의 return에 Student클래스의 인스턴스가 리턴되면서 자동으로 __repr_html_()실행학기: 4
iu + 1 + 0 + 0 + 0 학기: 5
__mul__
a=1
b=1
a*b1
a.__mul__<method-wrapper '__mul__' of int object at 0x70c560>
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def show(self):
print(self.actions[-1])
def _repr_html_(self):
html_str = """
낼 수 있는 패: {} <br/>
기록: {}
"""
return html_str.format(self.candidate,self.actions)a=RPS()
b=RPS()a기록: []
b기록: []
- a*b 해서 승패를 확인하기 위한 클래스를 만들자
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
self.results = list()
def __mul__(self,other):
self.choose()
other.choose()
if self.actions[-1]=='가위' and other.actions[-1]=='가위':
self.results.append(0)
other.results.append(0)
if self.actions[-1]=='가위' and other.actions[-1]=='바위':
self.results.append(-1)
other.results.append(1)
if self.actions[-1]=='가위' and other.actions[-1]=='보':
self.results.append(1)
other.results.append(-1)
if self.actions[-1]=='바위' and other.actions[-1]=='가위':
self.results.append(1)
other.results.append(-1)
if self.actions[-1]=='바위' and other.actions[-1]=='바위':
self.results.append(0)
other.results.append(0)
if self.actions[-1]=='바위' and other.actions[-1]=='보':
self.results.append(-1)
other.results.append(1)
if self.actions[-1]=='보' and other.actions[-1]=='가위':
self.results.append(-1)
other.results.append(1)
if self.actions[-1]=='보' and other.actions[-1]=='바위':
self.results.append(1)
other.results.append(-1)
if self.actions[-1]=='보' and other.actions[-1]=='보':
self.results.append(0)
other.results.append(0)
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def _repr_html_(self):
html_str = """
낼 수 있는 패: {} <br/>
액션: {} <br/>
승패: {}
"""
return html_str.format(self.candidate,self.actions,self.results)a=RPS()
b=RPS()a액션: []
승패: []
b액션: []
승패: []
for i in range(5):
a*ba액션: ['보', '바위', '가위', '가위', '바위']
승패: [1, 0, -1, 0, 1]
b액션: ['바위', '바위', '바위', '가위', '가위']
승패: [-1, 0, 1, 0, -1]
숙제
RPS클래스에서 player a와 player b를 만들어라. Player a는 [‘가위’,‘보’] 중에 하나를 낼 수 있다. 그리고 Player b는 [‘가위’,‘바위’] 중에 하나를 낼 수 있다. 두 player는 가지고 있는 패를 (같은확률로) 랜덤으로 낸다. (즉 player a가 가위만 내거나 보만 내는 경우는 없다.)
누가 더 유리한가? 이유를 스스로 생각해보라. (이유를 정리하여 숙제로 제출할 필요 없음)
50000번의 시뮬레이션을 해보고 결과를 분석해보라.
class RPS:
def __init__(self,candidate=['가위','바위','보']):
self.candidate = candidate
self.actions = list()
self.results = list()
def __mul__(self,other):
self.choose()
other.choose()
if self.actions[-1]=='가위' and other.actions[-1]=='가위':
self.results.append(0)
other.results.append(0)
if self.actions[-1]=='가위' and other.actions[-1]=='바위':
self.results.append(-1)
other.results.append(1)
if self.actions[-1]=='보' and other.actions[-1]=='가위':
self.results.append(-1)
other.results.append(1)
if self.actions[-1]=='보' and other.actions[-1]=='바위':
self.results.append(1)
other.results.append(-1)
def choose(self):
self.actions.append(np.random.choice(self.candidate))
def _repr_html_(self):
html_str = """
낼 수 있는 패: {} <br/>
액션: {} <br/>
승패: {}
"""
return html_str.format(self.candidate,self.actions,self.results)a=RPS(['가위','보'])
b=RPS(['가위','바위'])for i in range(50000):
a*bsum(a.results)-12358
sum(b.results)12358